import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;

/**
 * Smith Chart Plotter for 2N3478 S11 data
 * - Uses proper Swing threading (EDT)
 * - Responsive to window size
 * - Can be launched from another class (e.g. LaunchObject)
 */
public class SmithChartPlotter11_threaded {

    // S11 measurement data: [frequency Hz, Re(Γ), Im(Γ)]
    private static final double[][] POINTS = {
        {100000000,  0.3704,  -0.3274},
        {300000000,  -0.0323, -0.3423},
        {500000000,  -0.2124, -0.2591},
        {900000000,  -0.2667, -0.1422},
        {1300000000, -0.3140, 0.0192},
        {1700000000, -0.2837, 0.2948}
    };

    /**
     * Public method to safely open the Smith Chart window from anywhere
     */
    public static void launchSmithChart() {
        SwingUtilities.invokeLater(() -> createAndShowGUI());
    }

    private static void createAndShowGUI() {
        JFrame frame = new JFrame("Smith Chart - 2N3478 S11");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);  // Important: don't exit whole app

        SmithChartPanel chartPanel = new SmithChartPanel();
        frame.add(chartPanel);

        frame.setSize(700, 750);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    /**
     * The actual drawing panel - extends JPanel and handles all rendering
     */
    static class SmithChartPanel extends JPanel {

        public SmithChartPanel() {
            setBackground(Color.WHITE);
            setPreferredSize(new Dimension(650, 700));
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;

            // Enable smooth rendering
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

            // Get current panel dimensions
            int w = getWidth();
            int h = getHeight();

            // Center the chart and make it responsive
            int centerX = w / 2;
            int centerY = h / 2;
            int radius = Math.min(w, h) / 2 - 60;  // Leave some margin

            // Draw outer circle (|Γ| = 1)
            g2.setColor(Color.BLACK);
            g2.setStroke(new BasicStroke(2.0f));
            g2.draw(new Ellipse2D.Double(centerX - radius, centerY - radius, 2 * radius, 2 * radius));

            // Draw horizontal real axis
            g2.draw(new Line2D.Double(centerX - radius, centerY, centerX + radius, centerY));

            // Draw some constant resistance circles
            double[] resistances = {0.2, 0.5, 1.0, 2.0, 5.0};
            for (double r : resistances) {
                drawResistanceCircle(g2, centerX, centerY, radius, r);
            }

            // Plot the measured points and connect them
            g2.setColor(new Color(220, 20, 60));  // Crimson red
            g2.setStroke(new BasicStroke(3.0f));

            Point2D prevPoint = null;
            for (double[] measurement : POINTS) {
                double freqHz = measurement[0];
                double re = measurement[1];
                double im = measurement[2];

                Point2D point = gammaToPixel(re, im, centerX, centerY, radius);

                // Draw filled circle at point
                g2.fill(new Ellipse2D.Double(point.getX() - 7, point.getY() - 7, 14, 14));

                // Label with frequency in MHz
                long freqMHz = Math.round(freqHz / 1_000_000);
                g2.setColor(Color.BLACK);
                g2.setFont(new Font("SansSerif", Font.PLAIN, 13));
                g2.drawString(freqMHz + " MHz", (float) point.getX() + 12, (float) point.getY() - 10);

                // Connect to previous point with line
                if (prevPoint != null) {
                    g2.setColor(new Color(220, 20, 60));
                    g2.draw(new Line2D.Double(prevPoint, point));
                }
                prevPoint = point;
            }

            // Draw title
            g2.setColor(Color.BLACK);
            g2.setFont(new Font("SansSerif", Font.BOLD, 22));
            g2.drawString("Smith Chart - 2N3478 S11", centerX - 180, 50);
        }

        private Point2D gammaToPixel(double re, double im, int centerX, int centerY, int radius) {
            double x = centerX + re * radius;
            double y = centerY - im * radius;  // Invert Y-axis for screen coordinates
            return new Point2D.Double(x, y);
        }

        private void drawResistanceCircle(Graphics2D g2, int centerX, int centerY, int chartRadius, double r) {
            if (r <= 0) return;

            double cx = centerX + chartRadius * (r / (r + 1.0));
            double rad = chartRadius * (1.0 / (r + 1.0));

            g2.setColor(Color.GRAY);
            g2.setStroke(new BasicStroke(1.0f));
            g2.draw(new Ellipse2D.Double(cx - rad, centerY - rad, 2 * rad, 2 * rad));
        }
    }
}